package expr

import (
	"regexp"

	"github.com/antonmedv/expr/ast"
	"github.com/antonmedv/expr/parser"

	"github.com/spf13/cast"

	"gitee.com/zfd81/dbrs/expr/functions"
	"github.com/antonmedv/expr"
)

type visitor struct {
	identifiers []string
}

func (v *visitor) Enter(node *ast.Node) {}
func (v *visitor) Exit(node *ast.Node) {
	if n, ok := (*node).(*ast.IdentifierNode); ok {
		v.identifiers = append(v.identifiers, n.Value)
	}
}

func isInt(str string) bool {
	return regexp.MustCompile(`^\d+$`).MatchString(str)
}

func isFloat(str string) bool {
	return regexp.MustCompile(`^\d+[.]\d+$`).MatchString(str)
}

func isBool(str string) bool {
	return str == "true" || str == "false"
}
func Fields(str string) ([]string, error) {
	tree, err := parser.Parse(str)
	if err != nil {
		return nil, err
	}
	visitor := &visitor{}
	ast.Walk(&tree.Node, visitor)
	return visitor.identifiers, nil
}

func ConvertDataTypes(env map[string]interface{}) map[string]interface{} {
	for k, v := range env {
		if isInt(cast.ToString(v)) {
			env[k] = cast.ToInt(v)
		} else if isFloat(cast.ToString(v)) {
			env[k] = cast.ToFloat64(v)
		} else if isBool(cast.ToString(v)) {
			env[k] = cast.ToBool(v)
		}
	}
	return env
}

type VirtualMachine struct {
	options []expr.Option
	env     map[string]interface{}
}

func (vm *VirtualMachine) Eval(script string) (interface{}, error) {
	program, err := expr.Compile(script, vm.options...)
	if err != nil {
		return "", err
	}
	return expr.Run(program, vm.env)
}

func BuildVM(variables map[string]interface{}) *VirtualMachine {
	variables["if"] = functions.If
	variables["decode"] = functions.Decode
	variables["eq"] = functions.Equality

	//字符串函数
	variables["concat"] = functions.Concat
	variables["lower"] = functions.Lower
	variables["upper"] = functions.Upper
	variables["left"] = functions.Left
	variables["right"] = functions.Right
	variables["lpad"] = functions.Lpad
	variables["rpad"] = functions.Rpad
	variables["ltrim"] = functions.Ltrim
	variables["rtrim"] = functions.Rtrim
	variables["trim"] = functions.Trim
	variables["replace"] = functions.Replace
	variables["strcmp"] = functions.Strcmp
	variables["repeat"] = functions.Repeat
	variables["length"] = functions.Length
	variables["reverse"] = functions.Reverse
	variables["insert"] = functions.Insert
	variables["substr"] = functions.Substr
	variables["obj"] = functions.Object
	variables["split"] = functions.Split
	variables["splitn"] = functions.SplitN

	variables["num"] = functions.Number
	variables["time"] = functions.Time
	variables["now"] = functions.Now
	variables["sysdate"] = functions.Now
	variables["curdate"] = functions.Curdate
	variables["curtime"] = functions.Curtime

	variables["AddDays"] = functions.AddDays
	variables["DiffDay"] = functions.DiffDay

	//加号
	variables["Add_string_int"] = functions.Add_string_int
	variables["Add_int_string"] = functions.Add_int_string
	variables["Add_decimal_int"] = functions.Add_decimal_int
	variables["Add_int_decimal"] = functions.Add_int_decimal
	variables["Add_any_float"] = functions.Add_any_float
	variables["Add_float_any"] = functions.Add_float_any
	variables["Add_decimal_decimal"] = functions.Add_decimal_decimal

	//减号
	variables["Sub_string_int"] = functions.Sub_string_int
	variables["Sub_int_string"] = functions.Sub_int_string
	variables["Sub_decimal_int"] = functions.Sub_decimal_int
	variables["Sub_int_decimal"] = functions.Sub_int_decimal
	variables["Sub_any_float"] = functions.Sub_any_float
	variables["Sub_float_any"] = functions.Sub_float_any
	variables["Sub_decimal_decimal"] = functions.Sub_decimal_decimal
	variables["Sub_string_string"] = functions.Sub_string_string

	//乘号
	variables["Mul_string_int"] = functions.Mul_string_int
	variables["Mul_int_string"] = functions.Mul_int_string
	variables["Mul_decimal_int"] = functions.Mul_decimal_int
	variables["Mul_int_decimal"] = functions.Mul_int_decimal
	variables["Mul_any_float"] = functions.Mul_any_float
	variables["Mul_float_any"] = functions.Mul_float_any
	variables["Mul_decimal_decimal"] = functions.Mul_decimal_decimal
	variables["Mul_string_string"] = functions.Mul_string_string

	//除号
	variables["Div_string_int"] = functions.Div_string_int
	variables["Div_int_string"] = functions.Div_int_string
	variables["Div_decimal_int"] = functions.Div_decimal_int
	variables["Div_int_decimal"] = functions.Div_int_decimal
	variables["Div_any_float"] = functions.Div_any_float
	variables["Div_float_any"] = functions.Div_float_any
	variables["Div_decimal_decimal"] = functions.Div_decimal_decimal
	variables["Div_string_string"] = functions.Div_string_string

	//等于号
	variables["EQ_string_int"] = functions.EQ_string_int
	variables["EQ_string_float"] = functions.EQ_string_float

	//大于号
	variables["GT_any_int"] = functions.GT_any_int
	variables["GT_any_float"] = functions.GT_any_float

	//大于等于号
	variables["GTE_any_int"] = functions.GTE_any_int
	variables["GTE_any_float"] = functions.GTE_any_float

	//小于号
	variables["LT_any_int"] = functions.LT_any_int
	variables["LT_any_float"] = functions.LT_any_float

	//小于等于号
	variables["LTE_any_int"] = functions.LTE_any_int
	variables["LTE_any_float"] = functions.LTE_any_float

	options := []expr.Option{
		expr.Env(variables),
		expr.Operator("+", "AddDays"),
		expr.Operator("-", "DiffDay"),

		expr.Operator("+", "Add_string_int"),
		expr.Operator("+", "Add_int_string"),
		expr.Operator("+", "Add_decimal_int"),
		expr.Operator("+", "Add_int_decimal"),
		expr.Operator("+", "Add_any_float"),
		expr.Operator("+", "Add_float_any"),
		expr.Operator("+", "Add_decimal_decimal"),
		expr.Operator("-", "Sub_string_int"),
		expr.Operator("-", "Sub_int_string"),
		expr.Operator("-", "Sub_decimal_int"),
		expr.Operator("-", "Sub_int_decimal"),
		expr.Operator("-", "Sub_any_float"),
		expr.Operator("-", "Sub_float_any"),
		expr.Operator("-", "Sub_decimal_decimal"),
		expr.Operator("-", "Sub_string_string"),
		expr.Operator("*", "Mul_string_int"),
		expr.Operator("*", "Mul_int_string"),
		expr.Operator("*", "Mul_decimal_int"),
		expr.Operator("*", "Mul_int_decimal"),
		expr.Operator("*", "Mul_any_float"),
		expr.Operator("*", "Mul_float_any"),
		expr.Operator("*", "Mul_decimal_decimal"),
		expr.Operator("*", "Mul_string_string"),
		expr.Operator("/", "Div_string_int"),
		expr.Operator("/", "Div_int_string"),
		expr.Operator("/", "Div_decimal_int"),
		expr.Operator("/", "Div_int_decimal"),
		expr.Operator("/", "Div_any_float"),
		expr.Operator("/", "Div_float_any"),
		expr.Operator("/", "Div_decimal_decimal"),
		expr.Operator("/", "Div_string_string"),

		expr.Operator("==", "EQ_string_int"),
		expr.Operator("==", "EQ_string_float"),

		expr.Operator(">", "GT_any_int"),
		expr.Operator(">", "GT_any_float"),

		expr.Operator(">=", "GTE_any_int"),
		expr.Operator(">=", "GTE_any_float"),

		expr.Operator("<", "LT_any_int"),
		expr.Operator("<", "LT_any_float"),

		expr.Operator("<=", "LTE_any_int"),
		expr.Operator("<=", "LTE_any_float"),
	}
	return &VirtualMachine{
		env:     variables,
		options: options,
	}
}

func Eval(script string, env map[string]interface{}) (interface{}, error) {
	vm := BuildVM(env)
	return vm.Eval(script)
}
